package com.itcam.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.itcam.cammycommon.model.entity.UserInterfaceInfo;
import com.itcam.project.common.ErrorCode;
import com.itcam.project.exception.BusinessException;
import com.itcam.project.mapper.UserInterfaceInfoMapper;
import com.itcam.project.service.UserInterfaceInfoService;
import org.springframework.stereotype.Service;

/**
 * @author Cammy
 * @description 针对表【user_interface_info(用户调用接口关系)】的数据库操作Service实现
 * @createDate 2024-07-31 00:42:28
 */

@Service
public class UserInterfaceInfoServiceImpl extends ServiceImpl<UserInterfaceInfoMapper, UserInterfaceInfo>
        implements UserInterfaceInfoService {

    @Override
    public void validUserInterfaceInfo(UserInterfaceInfo userInterfaceInfo, boolean add) {
        // 判断接口信息对象是否为空，为空则抛出参数错误的异常
        if (userInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 如果是添加操作
        if (add) {
            if (userInterfaceInfo.getInterfaceInfoId() <= 0 || userInterfaceInfo.getUserId() <= 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "接口或用户不存在");
            }
        }
        if (userInterfaceInfo.getLeftNum() < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "剩余次数不能小于0");
        }

    }

    /**
     * 在这里需要注意的是，由于用户可能会瞬间调用大量接口次数，为了避免统计出错，需要涉及到事务和锁的只是。
     * 在这种情况下，如果我们是在分布式环境中运行的，那么可能需要使用分布式锁来保证数据的一致性。
     *
     * 事务是一组操作的集合，要么全部成功，要么全部失败回滚。
     * 在这个场景中，我们希望在更新用户接口信息的时候，保证原子性，即要么用户接口信息全部更新成功，要么全部不更新。
     *
     * 锁的作用是为了防止多个线程或进程同时修改同一个数据，造成数据不一致的情况。
     * 在分布式环境中，我们需要使用分布式锁来确保在多个节点上对数据的访问是互斥的。
     */
    /**
     * 调用接口统计
     *
     * @param interfaceInfoId
     * @param userId
     * @return
     */
    @Override
    public boolean invokeCount(long interfaceInfoId, long userId) {
        // 判断（其实这里还应该校验存不存在，但是这里就不用校验了，因为它不存在，也更新不到那条记录）
        if (interfaceInfoId <= 0 || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 使用 UpdateWrapper对象来构建更新条件
        UpdateWrapper<UserInterfaceInfo> updateWrapper = new UpdateWrapper<>();

        // 在 updateWrapper 中设置两个条件：interfaceInfoId等于给定的 interfaceInfoId 和 userId 等于给定的 userId
        updateWrapper.eq("interfaceInfoId", interfaceInfoId);
        updateWrapper.eq("userId", userId);

        // setSql 方法用于设置要更新的 SQL 语句。这里通过SQL表达式实现了两个字段的更新操作
        // leftNum = leftNum - 1 和 totalNum = totalNum + 1 意思是将leftNum字段减一，totalNum字段加一
        updateWrapper.setSql("leftNum = leftNum - 1, totalNum = totalNum + 1");

        // 最后，调用update方法执行更新操作，并返回更新是否成功的结果
        return this.update(updateWrapper);
    }
}




